import {
  Scene,
  WebGLRenderer,
  EventDispatcher,

  BoxGeometry,
  MeshStandardMaterial,
  Mesh,
} from 'three';
import Camera from '@/camera/Camera';
import { bindAll } from '@/utils/utils';

class Engine extends EventDispatcher {
  private _scene: Scene = new Scene();
  private _container: HTMLElement;
  private _renderer: WebGLRenderer;
  private _camera: Camera;
  private _renderTimer?: number;
  private _renderQueue: string[] = [];

  constructor(container: HTMLElement) {
    super();
    bindAll([
      '_draw',
    ], this);

    this._container = container;
    this._renderer = new WebGLRenderer({
      antialias: true,
      alpha: true,
    });
    this._renderer.setPixelRatio(devicePixelRatio);
    const rect = this._container.getBoundingClientRect();
    this._renderer.setSize(rect.width, rect.height);
    this._container.appendChild(this._renderer.domElement);

    this._camera = new Camera(rect.width, rect.height);
    this._test();
  }

  private _test() {
    const geometry = new BoxGeometry(10, 10, 10);
    const material = new MeshStandardMaterial({
      emissive: '#922cca',
    });
    const mesh = new Mesh(geometry, material);
    this._scene.add(mesh);
    this.render();
  }

  getScene() {
    return this._scene;
  }

  private _draw() {
    this._renderQueue.pop();
    this._renderer.render(this._scene, this._camera.getCamera());
    if (this._renderQueue.length !== 0) {
      this._renderTimer = requestAnimationFrame(this._draw);
    } else {
      delete this._renderTimer;
    }
  }

  private _startRender() {
    if (this._renderTimer) return;
    this._renderTimer = requestAnimationFrame(this._draw);
  }

  render() {
    if (this._renderQueue.length !== 0) return;
    this._renderQueue.push('render');
    this._startRender();
  }

  getContainer() {
    return this._container;
  }

  getCamera() {
    return this._camera;
  }
}

export default Engine;
